#include <chrono>
#include <filesystem>
#include <fstream>
#include <iomanip>
#include "async_logger.h"
#include "direct_io_strategy.h"
#include "file_output_strategy.h"
#include "gtest/gtest.h"
#include "mmap_output_strategy.h"

namespace Base {
namespace SystemLog {
namespace {
constexpr const char* TEST_LOG_DIR = "out/tests/logs";
constexpr const char TEST_CHAR = 't';
constexpr size_t TEST_MB = (1024 * 1024); // 1MB
constexpr size_t TEST_DATA_SIZE = 1 * 1024 * TEST_MB; // 1GB
constexpr size_t MESSAGE_SIZE = 4096; // 4KB
} // namespace

class IOPerformanceTest : public ::testing::Test {
protected:
    void SetUp() override {
        std::filesystem::create_directories(TEST_LOG_DIR);
    }

    void TearDown() override {
        for (const auto& entry : std::filesystem::directory_iterator(TEST_LOG_DIR)) {
            std::filesystem::remove_all(entry.path());
        }
    }

    void RunPerformanceTest(const std::string& testName, OutputStrategyPtr strategy) {
        AsyncLogger<>::GetInstance().AddOutputStrategy(std::move(strategy));

        // 准备测试数据
        std::vector<char> data(MESSAGE_SIZE, TEST_CHAR);

        // 启动日志器
        AsyncLogger<>::GetInstance().Start();

        // 预热
        for (int i = 0; i < 100; i++) {
            AsyncLogger<>::GetInstance().Append(data.data(), MESSAGE_SIZE);
        }

        // 正式测试
        size_t totalBytes = 0;
        auto start = std::chrono::high_resolution_clock::now();

        while (totalBytes < TEST_DATA_SIZE) {
            AsyncLogger<>::GetInstance().Append(data.data(), MESSAGE_SIZE);
            totalBytes += MESSAGE_SIZE;
        }

        // 等待日志刷新
        AsyncLogger<>::GetInstance().Flush();
        auto end = std::chrono::high_resolution_clock::now();

        // 停止日志器
        AsyncLogger<>::GetInstance().Stop();

        // 计算性能指标
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
        double seconds = static_cast<double>(duration) / 1000.0;
        double throughput = static_cast<double>(totalBytes / TEST_MB) / seconds;

        // 打印结果
        GTEST_LOG_(INFO) << '\n' <<
            "[PERFORMANCE REPORT]\n" <<
            "[" << testName << " Performance]\n" <<
            "Total data: " << (totalBytes / TEST_MB) << " MB\n" <<
            "Duration: " << duration << " ms\n" <<
            "Throughput: " << std::fixed << std::setprecision(2) <<
            throughput << " MB/s\n";
    }
};

/**
 * @tc.name: IOPerformanceTest_001
 * @tc.desc: FileOutputPerformance
 * @tc.type: PERF
 */
TEST_F(IOPerformanceTest, IOPerformanceTest_001) {
    FileOutputOptions options;
    options.filePathPattern = std::string(TEST_LOG_DIR) + "/file_perf.log";
    RunPerformanceTest("Standard File I/O", std::make_unique<FileOutputStrategy>(options));
}

/**
 * @tc.name: IOPerformanceTest_002
 * @tc.desc: MMapOutputPerformance
 * @tc.type: PERF
 */
TEST_F(IOPerformanceTest, IOPerformanceTest_002) {
    MMapOutputOptions options;
    options.filePathPattern = std::string(TEST_LOG_DIR) + "/mmap_perf.log";
    options.mappingSize = 128 * TEST_MB; // 128MB
    RunPerformanceTest("Memory Mapped File", std::make_unique<MMapOutputStrategy>(options));
}

/**
 * @tc.name: IOPerformanceTest_003
 * @tc.desc: DirectIOPerformance
 * @tc.type: PERF
 */
TEST_F(IOPerformanceTest, IOPerformanceTest_003) {
    DirectIOOptions options;
    options.filePathPattern = std::string(TEST_LOG_DIR) + "/directio_perf.log";
    RunPerformanceTest("Direct I/O", std::make_unique<DirectIOStrategy>(options));
}
} // namespace SystemLog
} // namespace Base